package com.education;

import java.io.IOException;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.handler.physics.PhysicsHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.IEntity;
import org.andengine.entity.IEntityMatcher;
import org.andengine.entity.modifier.LoopEntityModifier;
import org.andengine.entity.modifier.MoveModifier;
import org.andengine.entity.modifier.SequenceEntityModifier;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.AnimatedSprite.IAnimationListener;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.extension.svg.opengl.texture.atlas.bitmap.SVGBitmapTextureAtlasTextureRegionFactory;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BuildableBitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.source.IBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.buildable.builder.BlackPawnTextureAtlasBuilder;
import org.andengine.opengl.texture.atlas.buildable.builder.ITextureAtlasBuilder.TextureAtlasBuilderException;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.util.GLState;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.color.Color;
import org.andengine.util.modifier.ease.EaseBounceIn;
import org.andengine.util.modifier.ease.EaseCircularIn;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;

/* ИД всех букв
а 0
б 1
в 2
г 3
д 4
е 5
ё 6
ж 7
з 8
и 9
й 10
к 11
л 12
м 13
н 14
о 15
п 16
р 17
с 18
т 19
у 20
ф 21
х 22
ц 23
ч 24
ш 25
щ 26
ъ 27
ы 28
ь 29
э 30
ю 31
я 32
 */

public class MainActivity extends SimpleBaseGameActivity implements IAccelerationListener, IOnSceneTouchListener {
	// ===========================================================
	// Constants
	// ===========================================================
	//сдвиги по битсету до определенных флагов
	private final int IS = 6;
	private final int SOFTENING = 5;
	private final int FAIL_SOFTENING = 4;
	private final int SOUND_CHANGED = 3;
	private final int READ = 2;
	private final int FORBAD1 = 1;
	private final int FORBAD2 = 0;
	public int CAMERA_WIDTH  = 720;
	public int CAMERA_HEIGHT = 480;
	
	//пересчитать для разных разрешений
	public float scaleRatio = 0.7f;
	// ===========================================================
	// Fields
	// ===========================================================

	private Scene mScene;
	
	private MainActivity _main = this;
	
	//private int[][] words = {{13,0,13,0},{16,0,16,0},{1,0,1,0},{4,5,4,0},{32,1,12,15,11,15},{18,15,12,29}};
	//private int[][] words = {{18,15,12,29},{17,20,24,29,9},{16,15,4,27,5,8,4},{13,0,13,0},{16,0,16,0},{1,0,1,0},{4,5,4,0},{32,1,12,15,11,15},{18,15,12,29}};
	
	WordsDictionary dictionary;
	
	private int[] curWord;
	private letter[] guessLetters;
	private letter[] srcLetters;
	
	private boolean isAnimationPlaying = false; //TODO: пока не нужна
	private boolean isSoundPlaying = false;
	
	private Alphabet mAlphabet;
	private Sprite[] emptyLetterHolders;
	
	private Camera camera; 
	private HUD hud;
	private Rectangle block;
	private Rectangle imgHolder; 
	Sprite wordpic;
	
	public BuildableBitmapTextureAtlas mBuildableBitmapTextureAtlas;
	protected ITextureRegion mEmptyLetterHolder;
	
	private VertexBufferObjectManager vertexBufferObjectManager;
	
	private Sound successSound;
		
	@Override
	public EngineOptions onCreateEngineOptions() {

		WindowManager w = getWindowManager();
        Display d = w.getDefaultDisplay();

        CAMERA_WIDTH = d.getWidth();
        CAMERA_HEIGHT = d.getHeight();
        
        //Toast.makeText(this, String.format("Resolution is %d : %d", CAMERA_WIDTH, CAMERA_HEIGHT), Toast.LENGTH_SHORT).show();
        //Utilities.showToastFromBackground( String.format("Resolution is %d : %d", CAMERA_WIDTH, CAMERA_HEIGHT), this);
        Log.w("ONCREATEENGINEOPTIONS", String.format("Resolution is %d : %d", CAMERA_WIDTH, CAMERA_HEIGHT));
		camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions en = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera); 
		
		en.getAudioOptions().setNeedsSound(true);
		
		return en;
	}

	@Override
	public void onCreateResources() {
		SVGBitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		//TODO: типа загружаем текстуры и звуки алфавита, но надо ли
		mAlphabet = new Alphabet(this);
		
		this.mBuildableBitmapTextureAtlas = new BuildableBitmapTextureAtlas(this.getTextureManager(), 2048, 1024, TextureOptions.NEAREST);
		this.mEmptyLetterHolder = SVGBitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBuildableBitmapTextureAtlas, this, "empty_letter_holder.svg", (int)(195*scaleRatio), (int)(278*scaleRatio));

		try {
			this.mBuildableBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(1, 1, 1));
		} catch (TextureAtlasBuilderException e) {
			// TODO TextureAtlasBuilderException Auto-generated catch block
			e.printStackTrace();
		}
		
		this.mBuildableBitmapTextureAtlas.load();
		
		SoundFactory.setAssetBasePath("snd/");
		//SOUND
//		try
//		{
//			successSound = SoundFactory.createSoundFromAsset(this.getSoundManager(), this.getApplicationContext(),"Clapping.mp3");
//			//TODO: добавить остальные звуки
//		} catch (IOException e)
//		{
//			e.printStackTrace();
//		}
	}
	
	@Override
	public Scene onCreateScene() {
		
		this.mEngine.registerUpdateHandler(new FPSLogger());
		vertexBufferObjectManager = this.getVertexBufferObjectManager();
		
		//интерфейсная сцена
		hud = new HUD();
		camera.setHUD(hud);

		this.mScene = new Scene();
		this.mScene.setBackground(new Background(1f, 1f, 1f));
		this.mScene.setOnSceneTouchListener(this);
		
		this.mScene.setTouchAreaBindingOnActionDownEnabled(true);
		
		try {
			this.dictionary = new WordsDictionary(this, "json/dict.json");
			/*{"word":[17,20,24,29,9],"sound":"Clapping.mp3","image":"word1.svg"},	
			{"word":[18,15,12,29],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[16,15,4,27,5,8,4],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[13,0,13,0],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[16,0,16,0],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[1,0,1,0],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[4,5,4,0],"sound":"Clapping.mp3","image":"word1.svg"},
			{"word":[32,1,12,15,11,15],"sound":"Clapping.mp3","image":"word1.svg"}*/
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		imgHolder = new Rectangle(0, -((CAMERA_HEIGHT/3)*2), CAMERA_WIDTH, (CAMERA_HEIGHT/3)*2, vertexBufferObjectManager)
		{
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (!isSoundPlaying)
				{
					//android.os.Process.killProcess(android.os.Process.myPid());
					//moveSpriteTo(this, 0, -((CAMERA_HEIGHT/3)*2), 3f);
					_main.mScene.clearTouchAreas();
					final LoopEntityModifier entityModifier =
			                new LoopEntityModifier(new SequenceEntityModifier(
			                            new MoveModifier(3f, this.getX(), 0, this.getY(), -((CAMERA_HEIGHT/3)*2), EaseCircularIn.getInstance())
			                		), 1
			                ){
						@Override
						protected void onModifierStarted(IEntity pItem) {
							// TODO Auto-generated method stub
							super.onModifierStarted(pItem);
							block.setPosition(0, 0);
							_main.clearScene();
							_main.getNewWord();
						}
						
						@Override
						protected void onModifierFinished(IEntity pItem) {
							// TODO Auto-generated method stub
							super.onModifierFinished(pItem);
							block.setPosition(CAMERA_WIDTH, 0);
						}
					};
					this.registerEntityModifier(entityModifier);
					PhysicsHandler physicsHandler = new PhysicsHandler(this);
					this.registerUpdateHandler(physicsHandler);
				}
				return true;
			}
		};
		imgHolder.setColor(Color.WHITE);
		this.hud.attachChild(imgHolder);
		
		block = new Rectangle(CAMERA_WIDTH, 0, CAMERA_WIDTH, CAMERA_HEIGHT, vertexBufferObjectManager)
		{	
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				return true;
			}
		};
		
		block.setColor(Color.RED);
		block.setAlpha(0.1f);

		this.hud.attachChild(block);
		this.mScene.registerTouchArea(block);
		
		getNewWord();
		
		imgHolder.attachChild(wordpic);		
		wordpic.setX(imgHolder.getWidth()/2-wordpic.getWidth()/2);
		wordpic.setY(imgHolder.getHeight()/2-wordpic.getHeight()/2);
		
		return this.mScene;
	}
	
//	@Override
//	protected void onCreate(Bundle pSavedInstanceState) {
//		// TODO Auto-generated method stub
//		super.onCreate(pSavedInstanceState);
//		this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
//        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
//	}
	
//	@Override
//	public boolean dispatchKeyEvent(KeyEvent event) {
//		return true;
//	}
//	
//	@Override
//	public boolean onKeyDown(int keyCode, KeyEvent event)  {
//	    return true;
//	}
//	
//	@Override
//	public boolean onKeyUp(int keyCode, KeyEvent event) {
//		return true;
//	}
	
	@Override
	public void onBackPressed() {
        android.os.Process.killProcess(android.os.Process.myPid());
		return;
	}
	
//	@Override
//	public void onAttachedToWindow() {
//		// TODO Auto-generated method stub
//		//super.onAttachedToWindow();
//		KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
//	    KeyguardLock lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
//	    lock.disableKeyguard();
//
//	}
	
	@Override
	protected void onDestroy() {
	    super.onDestroy();
//	        android.os.Process.killProcess(android.os.Process.myPid());
	}
	
	@Override
	public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
		return false;
	}

	@Override
	public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) {
		
	}

	@Override
	public void onAccelerationChanged(final AccelerationData pAccelerationData) {
	}

	@Override
	public void onResumeGame() {
		super.onResumeGame();

		this.enableAccelerationSensor(this);
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();

		this.disableAccelerationSensor();
	}

	// ===========================================================
	// Methods
	// ===========================================================
	
	public void clearScene()
	{
		_main.mScene.detachChildren();
		_main.mScene.clearEntityModifiers();
		_main.mScene.clearTouchAreas();
		_main.mScene.clearUpdateHandlers();
		_main.mScene.reset();
	}
	
	public void getNewWord()
	{
		//TODO: тупая защита от несанкционированного запуска getNewWord, когда на сцене уже/еще есть слово.
		if (this.mScene.getChildCount()>2)
		{
			return;
		}
		WordsDictionary.Word newWord = this.dictionary.getWord();
		wordpic = newWord.image;
		successSound = newWord.sound;
		this.mScene.registerTouchArea(block);
		
		//static graphics content
		//TODO: по возможности перенести в статичную сцену
		final Rectangle letters_holder = new Rectangle(0, CAMERA_HEIGHT - CAMERA_HEIGHT/3, CAMERA_WIDTH, CAMERA_HEIGHT/3, vertexBufferObjectManager);
		letters_holder.setColor(0.867f, 0.745f, 0.765f);
		this.mScene.attachChild(letters_holder);
		
		curWord = newWord.letters;
		guessLetters = new letter[curWord.length];
		srcLetters =  new letter[curWord.length];
		
		emptyLetterHolders = new Sprite[this.curWord.length];
		Sprite[] curWordLetters = new Sprite[this.curWord.length];
		final float centerX =  CAMERA_WIDTH/2;
		final float centerY =  CAMERA_HEIGHT/2;
		boolean even = (this.curWord.length & 1) == 0;
		float holderWidth = this.mEmptyLetterHolder.getWidth();
		float holderHeight = this.mEmptyLetterHolder.getHeight();
		float x = 0;
		float topY = 0;
		float middleY = 0;
		float bottomY = 0;
		//=======
		//рисуем буквоместа, слово и набор карточек с буквами
		//=======
		//возвращает перемешанный массив индексов от 0 до длины текущего слова
		int[] shuffledWord = Utilities.shuffle(curWord.length);
		
		for (int i=0;i<this.curWord.length;i++)
		{
			if (i<this.curWord.length/2)
			{
				x = centerX - ((this.curWord.length/2-i)*holderWidth);
			} else
			{
				x = centerX + ((i-this.curWord.length/2)*holderWidth);
			}
			
			x = even?x:x-holderWidth/2;
			topY = centerY-CAMERA_HEIGHT/3-holderHeight/2;
			middleY = centerY-holderHeight/2;
			bottomY = centerY+CAMERA_HEIGHT/3-holderHeight/2;
			emptyLetterHolders[i] = new Sprite(x,middleY,this.mEmptyLetterHolder,vertexBufferObjectManager);
			emptyLetterHolders[i].setAlpha(0.5f);
			curWordLetters[i] = new Sprite(x,topY,Alphabet.mLettersTextureRegions[curWord[i]],vertexBufferObjectManager);
			this.srcLetters[i] = new letter(this.curWord[shuffledWord[i]],this, x, bottomY);//ID буквы берем из перемешанного списка букв слова
			this.srcLetters[i].srcPos = i;
			_main.mScene.attachChild(emptyLetterHolders[i]);
			_main.mScene.attachChild(curWordLetters[i]);
			_main.mScene.attachChild(this.srcLetters[i].sprite);
			//moveSpriteTo(curWordLetters[i], x, topY,0.3f);
			this.srcLetters[i].sprite.setPosition(x+CAMERA_WIDTH, bottomY);
			moveSpriteTo(this.srcLetters[i].sprite, x, bottomY,1.3f+x/400);
			this.mScene.registerTouchArea(this.srcLetters[i].sprite);
		}
	}
	
	public boolean onAreaTouched(final letter curLetter, final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY, final float curX, final float curY)
	{
		//проверяем, если буква еще лежит на базе (-1) и еще не лежит на том месте где ей положено, то ее можно двигать
		if (curLetter.guessPos==-1 || curLetter.id !=_main.curWord[curLetter.guessPos])
		{
			if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE)
			{
				final letter prevLetter = curLetter.guessPos>0?_main.guessLetters[curLetter.guessPos-1]:null;
				final letter nextLetter = curLetter.guessPos>=0&&curLetter.guessPos<_main.curWord.length-1?_main.guessLetters[curLetter.guessPos+1]:null;
				if(curLetter.guessPos>-1)//если начинаем двигать, то значит с места убираем букву, все позиции обнуляем
				{
					_main.guessLetters[curLetter.guessPos] = null;
					//сбрасываем звук и анимацию смягчения
					curLetter.unChangeSound();
					//сбрасываем звук и анимацию смягчения у соседних букв
					if (prevLetter!=null)
					{
						prevLetter.unChangeSound();
					}
					if (nextLetter!=null)
					{
						nextLetter.unChangeSound();
					}
					curLetter.guessPos=-1;					
				}
				//двигаем букву
				curLetter.sprite.setPosition(pSceneTouchEvent.getX() - curLetter.sprite.getWidth() / 2, pSceneTouchEvent.getY() - curLetter.sprite.getHeight() / 2);
			} else if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_UP)
			{
				for (int i=0;i<_main.guessLetters.length;i++)
				{
					if (_main.guessLetters[i]==null)
					{
						Sprite s = emptyLetterHolders[i];
						//калибровочные сдвиги для вычисления попадания спрайта в буквоместо
						final double xoffset = curLetter.sprite.getWidth()/2;
						final double yoffset = curLetter.sprite.getHeight()/2;
						// если попали буквой в буквоместо
						if ((curLetter.sprite.getX()+xoffset>s.getX()&&curLetter.sprite.getX()+xoffset<s.getX()+s.getWidth()) && (curLetter.sprite.getY()+yoffset>s.getY()&&curLetter.sprite.getY()+yoffset<s.getY()+s.getHeight()))
						{
							curLetter.sprite.setPosition(s.getX(),s.getY());
							_main.guessLetters[i]=curLetter; // заполняем массив "слОва-догадки".
							curLetter.guessPos = i;
							final letter prevLetter = i>0?_main.guessLetters[i-1]:null;
							final letter nextLetter = i>=0&&i<_main.curWord.length-1?_main.guessLetters[i+1]:null;
							if (!isSoundPlaying)
							{
								processLetters(new letter[]{prevLetter, curLetter, nextLetter}, 0);
							}
						}
					}
				}
				
				//если бросили букву мимо букво места, то возвращаем ее на исходное место
				if (curLetter.guessPos==-1)
				{
					moveSpriteTo(curLetter.sprite, curX, curY,0.3f);
				}
			} else if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_DOWN)
			{
				//зачитываем букву из алфавита
				final Timer readTimer;
				readTimer = new Timer();
				block.setPosition(0, 0);
				//moveSpriteTo(curLetter.sprite, curLetter.sprite.getX(), curLetter.sprite.getY()-curLetter.sprite.getHeight()/4);
				isSoundPlaying = true;
				curLetter.alphabetSound.play();		
				readTimer.schedule(new TimerTask() {
					@Override
					public void run() {
						block.setPosition(CAMERA_WIDTH, 0);
						//moveSpriteTo(curLetter.sprite, curLetter.sprite.getX(), curLetter.sprite.getY()+curLetter.sprite.getHeight()/4);
						isSoundPlaying = false;
						//если после отыгрыша буквы она уже легла на позицию, запускаем обработку букв
						if (curLetter.guessPos!=-1)
						{
							final letter prevLetter = curLetter.guessPos>0?_main.guessLetters[curLetter.guessPos-1]:null;
							final letter nextLetter = curLetter.guessPos>=0&&curLetter.guessPos<_main.curWord.length-1?_main.guessLetters[curLetter.guessPos+1]:null;
							processLetters(new letter[]{prevLetter, curLetter, nextLetter}, 0);
						}
					}
				}, 2000);
			}
		}
		
		for (int i=0;i<_main.curWord.length;i++)
		{
			//перекрашиваем буквоместо в зависимости от ситуации
			if (_main.guessLetters[i]==null)
			{
				emptyLetterHolders[i].setAlpha(0.5f);
			} else if (_main.curWord[i]!=_main.guessLetters[i].id)
			{
				emptyLetterHolders[i].setAlpha(1f);
			} else if (_main.curWord[i]==_main.guessLetters[i].id)
			{
				emptyLetterHolders[i].setAlpha(0f);
			}
		}
		return true;
	}
	
	private boolean isDone()
	{
		for (int i=0;i<_main.curWord.length;i++)
		{
			//если в текущей позиции вобще не стоит буква или стоит нессответсвующая буква
			if (_main.guessLetters[i]==null || _main.curWord[i]!=_main.guessLetters[i].id)
			{
				return false; //помечаем, что слово не разгадано
			}
		}
		return true;
	}
	
	private void showWordpic()
	{
		//читаем "разгаданное" слово
		_main.successSound.play();
		//FIXME: Картинка слова не меняется при смене слова, вероятно ниже решение, надо раскоментить и протестировать
//		if (wordpic.hasParent())
//		{
//			wordpic.detachSelf();
//		}
//		imgHolder.attachChild(wordpic);
//		this.mScene.registerTouchArea(imgHolder);
//		wordpic.setX(imgHolder.getWidth()/2-wordpic.getWidth()/2);
//		wordpic.setY(imgHolder.getHeight()/2-wordpic.getHeight()/2);
		final LoopEntityModifier entityModifier =
                new LoopEntityModifier(new SequenceEntityModifier(
                            new MoveModifier(3f, imgHolder.getX(), 0, imgHolder.getY(), 0, EaseCircularIn.getInstance())
                		), 1
                ) {
			@Override
			protected void onModifierFinished(IEntity pItem) {
				super.onModifierFinished(pItem);
				mScene.registerTouchArea(imgHolder);
			}
		};
		imgHolder.registerEntityModifier(entityModifier);
		PhysicsHandler physicsHandler = new PhysicsHandler(imgHolder);
		imgHolder.registerUpdateHandler(physicsHandler);
		//moveSpriteTo(imgHolder, 0, 0, 3f);
	}
	
	private void moveSpriteTo(IEntity entity, float toX, float toY, float duration)
	{
		final LoopEntityModifier entityModifier =
                new LoopEntityModifier(new SequenceEntityModifier(
                            new MoveModifier(duration, entity.getX(), toX, entity.getY(), toY, EaseCircularIn.getInstance())
                		), 1
                );
		entity.registerEntityModifier(entityModifier);
		PhysicsHandler physicsHandler = new PhysicsHandler(entity);
		entity.registerUpdateHandler(physicsHandler);
	}
	
	public void readLetter(final letter[] letters, final int curProcessedLetter)
	{
		Log.w("READLETTER", String.format("reading letter %d", letters[curProcessedLetter]==null?-1:letters[curProcessedLetter].id));
		
		int actions = Alphabet.alphabetEngineTabel[letter.getEngineIdx(letters[0])][letter.getEngineIdx(letters[1])][letter.getEngineIdx(letters[2])];
		final letter curLetter = letters[curProcessedLetter];
		if (((actions>>7*(2-curProcessedLetter)+SOUND_CHANGED) & 1)!=0)
		{
			Log.w("READLETTER", String.format("sound changed"));
			// 5	6
			// 1	0	ы
			// 1	1	йи
			if ((((actions>>7*(2-curProcessedLetter)+SOUND_CHANGED) & 1)!=0)&&(((actions>>7*(2-curProcessedLetter)+FORBAD1) & 1)!=0))
			{
				int badIndex = (((actions>>7*curProcessedLetter+FORBAD1) & 1)!=0)&&(((actions>>7*(2-curProcessedLetter)+FORBAD2) & 1)!=0)?1:2;
				letters[curProcessedLetter].changeSound(badIndex);
			} else if (((actions>>7*(2-curProcessedLetter)+SOUND_CHANGED) & 1)!=0)
			{
				letters[curProcessedLetter].changeSound();
			}
		}
		
		if (((actions>>7*(2-curProcessedLetter)+READ) & 1)!=0)
		{
			final Timer readTimer;
			readTimer = new Timer();
			block.setPosition(0, 0);
			moveSpriteTo(curLetter.sprite, curLetter.sprite.getX(), curLetter.sprite.getY()-curLetter.sprite.getHeight()/4,0.3f);
			curLetter.currsound.play();
			Log.w("READLETTER", String.format("sound playing"));
			readTimer.schedule(new TimerTask() {
				@Override
				public void run() {
					block.setPosition(CAMERA_WIDTH, 0);
					moveSpriteTo(curLetter.sprite, curLetter.sprite.getX(), curLetter.sprite.getY()+curLetter.sprite.getHeight()/4,0.3f);
					if (curProcessedLetter<2)
					{
						Log.w("READLETTER", String.format("sound ended"));
						processLetters(letters, curProcessedLetter+1);
					} else 
					//отгадали слово!
					if (_main.isDone())
					{
						showWordpic();
					}
				}
			}, 2000);
		} else 
		{
			if (curProcessedLetter<2)
			{
				processLetters(letters, curProcessedLetter+1);
			} else 
			//отгадали слово!
			if (_main.isDone())
			{
				showWordpic();
			}
		}
	}	
	
	public void softening(letter[] letters, int curProcessedLetter /*0 1 2*/)
	{
		softening(true,letters,curProcessedLetter);
	}
	
	public void softening(boolean isSofted, final letter[] letters, final int curProcessedLetter /*0 1 2*/)
	{
		//BitSet[] actions = Alphabet.alphabetEngineTabel[letters[0].getEngineIdx()][letters[1].getEngineIdx()][letters[2].getEngineIdx()];
		//BitSet curActions = actions[curProcessedLetter];
		final AnimatedSprite vowelSoftAnim = (AnimatedSprite)letters[curProcessedLetter+1].sprite.getChildByIndex(0);
		final AnimatedSprite consonantSoftAnim = (AnimatedSprite)letters[curProcessedLetter].sprite.getChildByIndex(0);
    	if (isSofted)
		{
    		IAnimationListener animListen = new IAnimationListener() {
					
					@Override
					public void onAnimationStarted(AnimatedSprite pAnimatedSprite,
							int pInitialLoopCount) {
						_main.isAnimationPlaying = true;
						block.setPosition(0, 0);					
					}
					
					@Override
					public void onAnimationLoopFinished(AnimatedSprite pAnimatedSprite,
							int pRemainingLoopCount, int pInitialLoopCount) {
						// TODO Auto-generated method stub
						
					}
					
					@Override
					public void onAnimationFrameChanged(AnimatedSprite pAnimatedSprite,
							int pOldFrameIndex, int pNewFrameIndex) {
						// TODO Auto-generated method stub
						
					}
					
					@Override
					public void onAnimationFinished(AnimatedSprite pAnimatedSprite) {
						_main.isAnimationPlaying = false;
						vowelSoftAnim.setVisible(false);//спрятать спрайт после отыгрыша смягчения
						consonantSoftAnim.setVisible(true);
						block.setPosition(CAMERA_WIDTH, 0);
						readLetter(letters, curProcessedLetter);
					}
				};
				vowelSoftAnim.animate(180,false,animListen);
		} else {
			//showToastFromBackground("Неудачное смягчение");
			IAnimationListener animListen = new IAnimationListener() {
				
				@Override
				public void onAnimationStarted(AnimatedSprite pAnimatedSprite,
						int pInitialLoopCount) {
					_main.isAnimationPlaying = true;
					block.setPosition(0, 0);
				}
				
				@Override
				public void onAnimationLoopFinished(AnimatedSprite pAnimatedSprite,
						int pRemainingLoopCount, int pInitialLoopCount) {
					// TODO Auto-generated method stub
					
				}
				
				@Override
				public void onAnimationFrameChanged(AnimatedSprite pAnimatedSprite,
						int pOldFrameIndex, int pNewFrameIndex) {
					if (pNewFrameIndex>4)
					{
						pAnimatedSprite.stopAnimation();
					}
				}
				
				@Override
				public void onAnimationFinished(AnimatedSprite pAnimatedSprite) {
					_main.isAnimationPlaying = false;
					pAnimatedSprite.animate(new long[]{180,180,180,180}, new int[]{3,2,1,0},false);
					block.setPosition(CAMERA_WIDTH, 0);
					readLetter(letters, curProcessedLetter);
				}
			};
			vowelSoftAnim.animate(new long[]{180,180,180,180},new int[]{0,1,2,3},false,animListen);			
		}
	}
	
	public void processLetters(letter[] letters, int curProcessedLetter /*0 1 2*/)
	{
		if (letters[curProcessedLetter]==null&&curProcessedLetter<2)
		{
			curProcessedLetter+=1;
		}
		
		if (letters[curProcessedLetter]==null&&_main.isDone())
		{
			showWordpic();
		}
		Log.w("PROCESS_LETTERS", String.format("Letters: %d, %d, %d. Current: %d", letters[0]==null?-1:letters[0].id,letters[1]==null?-1:letters[1].id, letters[2]==null?-1:letters[2].id, letters[curProcessedLetter]==null?-1:letters[curProcessedLetter].id));
		//0:is	1:softning	2:fail_softning	3:sound_changed	4:read	5,6:for_i
		// (value >> 7*letterpos+actionpos)
		// letterpos - 2 1 0
		// actionpos - 6-is 5-softening 4-fail_softening 3-sound_changed 2-read 1-forbad1 0-forbad1
		int actions = Alphabet.alphabetEngineTabel[letter.getEngineIdx(letters[0])][letter.getEngineIdx(letters[1])][letter.getEngineIdx(letters[2])];
		//letter curLetter = letters[curProcessedLetter];
		if (((actions>>7*(2-curProcessedLetter)+IS) & 1)!=0)
		{
			if (((actions>>7*(2-curProcessedLetter)+SOFTENING) & 1)!=0)
			{
				softening(letters, curProcessedLetter);
			} else if (((actions>>7*(2-curProcessedLetter)+FAIL_SOFTENING) & 1)!=0)
			{
				softening(false, letters, curProcessedLetter);
			} else if (((actions>>7*(2-curProcessedLetter)+READ) & 1)!=0)
			{
				readLetter(letters, curProcessedLetter);
			} else 
			{
				if (curProcessedLetter<2)
				{
					processLetters(letters,curProcessedLetter+1);
				} else if (_main.isDone()) //отгадали слово!
				{
					showWordpic();
				}
			}
		}
	}
	
	
	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}
